package cn.changeforyou.web.dao.mybatis.ext.extBuilder.sqlUtils;

import cn.changeforyou.web.dao.mybatis.ext.extBuilder.SqlContext;
import cn.changeforyou.web.dao.mybatis.ext.extBuilder.writer.SqlBuilder;
import cn.changeforyou.web.dao.mybatis.ext.metaInfo.ConditionCombineFieldMetaInfo;
import cn.changeforyou.web.dao.mybatis.ext.metaInfo.ConditionFieldMetaInfo;
import cn.changeforyou.web.dao.mybatis.ext.metaInfo.FieldColumnInfo;
import cn.changeforyou.web.dao.mybatis.ext.metaInfo.FieldMetaInfo;
import cn.changeforyou.web.dao.mybatis.ext.metaInfo.condition.ConditionType;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author zhyu
 * @version 1.0
 * @date 2022/3/7 12:43
 */
public class WhereUtils {
    /**
     * 构建between
     *
     * @param context
     * @param key2MetaInfoMap
     * @param expression
     * @param metaInfo
     */
    public static void buildBetween(SqlContext context, Map<String, ConditionFieldMetaInfo> key2MetaInfoMap, Set<String> expression,
                                    ConditionCombineFieldMetaInfo metaInfo) {
        String leftBetween = metaInfo.getLeftBetween();
        String leftAnd = metaInfo.getLeftAnd();
        String rightAnd = metaInfo.getRightAnd();
        SqlBuilder sql = context.getSql();
        String currentJavaParamPrefix = context.getCurrentJavaParamPrefix();

        boolean or = metaInfo.isOr();
        sql.append(or ? " or " : " and ");
        if (expression.contains(leftBetween)) {
            sql.append(" ").append(leftBetween);
        } else {
            ONGLUtils.buildMybatisVar(key2MetaInfoMap.get(leftBetween).getFieldName(), sql, currentJavaParamPrefix);
        }

        sql.append(" between");

        if (expression.contains(leftAnd)) {
            sql.append(" ").append(leftAnd);
        } else {
            ONGLUtils.buildMybatisVar(key2MetaInfoMap.get(leftAnd).getFieldName(), sql, currentJavaParamPrefix);
        }

        sql.append(" and");

        if (expression.contains(rightAnd)) {
            sql.append(" ").append(rightAnd);
        } else {
            ONGLUtils.buildMybatisVar(key2MetaInfoMap.get(rightAnd).getFieldName(), sql, currentJavaParamPrefix);
        }
    }

    /**
     * 构建if test标签后半部分
     *
     * @param context
     */
    public static void buildIfTestPostfix(SqlContext context) {
        context.getSql().append("\n</if>");
    }

    /**
     * 构建if test标签前半部分
     *
     * @param sqlContext
     * @param fieldColumnInfoList
     */
    public static void buildIfTestPrefix(SqlContext sqlContext, FieldColumnInfo... fieldColumnInfoList) {
        SqlBuilder sql = sqlContext.getSql();
        sql.append("\n<if test=\"");

        String currentJavaParamPrefix = sqlContext.getCurrentJavaParamPrefix();
        for (int i = 0; i < fieldColumnInfoList.length; i++) {
            FieldColumnInfo fieldColumnInfo = fieldColumnInfoList[i];
            String fieldName = fieldColumnInfo.getFieldName();
            Class fieldClass = fieldColumnInfo.getFieldClass();
            if (null != currentJavaParamPrefix) {
                if (i == 0) {
                    sql.append(currentJavaParamPrefix);
                } else {
                    sql.append(" ").append(currentJavaParamPrefix);
                }
                sql.append(".");
            }

            sql.append(fieldName).append(
                    " != null");
            if (fieldClass.isAssignableFrom(CharSequence.class)) {
                sql.append(" and ");
                if (null != currentJavaParamPrefix) {
                    sql.append(currentJavaParamPrefix).append(".");
                }
                sql.append(fieldName).append(
                        " != ''");
            } else if (fieldClass.isAssignableFrom(List.class)) {
                sql.append(" and ");
                if (null != currentJavaParamPrefix) {
                    sql.append(currentJavaParamPrefix).append(".");
                }
                sql.append(fieldName).append(
                        ".size() != 0");
            }
        }
        sql.append("\">");
    }

    /**
     * 构建操作符表达式
     *
     * @param sqlContext
     * @param fieldMetaInfo
     */
    public static void buildOperatorExpression(SqlContext sqlContext, FieldMetaInfo fieldMetaInfo) {
        ConditionType type = ConditionType.equal;
        SqlBuilder sql = sqlContext.getSql();
        String currentJavaParamPrefix = sqlContext.getCurrentJavaParamPrefix();
        String fieldName = fieldMetaInfo.getFieldName();
        sql.append(" and ");
        ColumnsUtils.writeColumnsInSelectSentence(sql, fieldMetaInfo);
        buildWhereExpressionOperatorBody(sql, type, fieldName, currentJavaParamPrefix);
    }

    /**
     * 构建操作符表达式
     *
     * @return
     */
    public static void buildOperatorExpression(SqlContext context, ConditionFieldMetaInfo conditionFieldMetaInfo) {
        boolean appendOrColumnIsNull = conditionFieldMetaInfo.isAppendOrColumnIsNull();
        ConditionType type = conditionFieldMetaInfo.getType();
        String fieldName = conditionFieldMetaInfo.getFieldName();
        boolean or = conditionFieldMetaInfo.isOr();
        SqlBuilder sql = context.getSql();
        String currentJavaParamPrefix = context.getCurrentJavaParamPrefix();
        sql.append(or ? " or " : " and ");
        if (appendOrColumnIsNull) {
            sql.append("(");
            ColumnsUtils.writeColumnsInSelectSentence(sql, conditionFieldMetaInfo);
            sql.append(" is null or (");
        }
        ColumnsUtils.writeColumnsInSelectSentence(sql, conditionFieldMetaInfo);
        if (type == ConditionType.in || type == ConditionType.notIn) {
            //todo 处理in或not in
        } else {
            buildWhereExpressionOperatorBody(sql, type, fieldName, currentJavaParamPrefix);
        }
        if (appendOrColumnIsNull) {
            sql.append("))");
        }
    }

    /**
     * 构建简单的if test脚本
     *
     * @param context
     * @param columnName
     * @param fieldName
     * @param fieldClass
     */
    public static void buildEasyIfTestScript(SqlContext context, String columnName,
                                             String fieldName, Class fieldClass) {
        SqlBuilder sql = context.getSql();
        String currentJavaParamPrefix = context.getCurrentJavaParamPrefix();
        buildIfTestPrefix(sql, fieldName, fieldClass, currentJavaParamPrefix);
        sql.append(" and").append(" ").append(columnName).append(" =").append(" #{").append(currentJavaParamPrefix).append(".")
                .append(fieldName).append("}");
        buildIfTestPostfix(context);
    }


    /**
     * 构建操作符相关的本体
     *
     * @param sql
     * @param type
     * @param fieldName
     * @param javaParamPrefix
     */
    public static void buildWhereExpressionOperatorBody(SqlBuilder sql, ConditionType type, String fieldName, String javaParamPrefix) {
        switch (type) {
            case leftLike:
                sql.append(" like");
                sql.append(" concat('%',");
                ONGLUtils.buildMybatisVar(fieldName, sql, javaParamPrefix);
                sql.append(")");
                break;
            case rightLike:
                sql.append(" like");
                sql.append(" concat(");
                ONGLUtils.buildMybatisVar(fieldName, sql, javaParamPrefix);
                sql.append(" , '%')");
                break;
            case like:
                sql.append(" like");
                sql.append(" concat('%',");
                ONGLUtils.buildMybatisVar(fieldName, sql, javaParamPrefix);
                sql.append(" , '%')");
                break;
            case notLeftLike:
                sql.append(" not like");
                sql.append(" concat('%',");
                ONGLUtils.buildMybatisVar(fieldName, sql, javaParamPrefix);
                sql.append(")");
                break;
            case notRightLike:
                sql.append(" not like");
                sql.append(" concat(");
                ONGLUtils.buildMybatisVar(fieldName, sql, javaParamPrefix);
                sql.append(" , '%')");
                break;
            case notLike:
                sql.append(" not like");
                sql.append(" concat('%',");
                ONGLUtils.buildMybatisVar(fieldName, sql, javaParamPrefix);
                sql.append(" , '%')");
                break;
            case equal:
                sql.append(" =");
                ONGLUtils.buildMybatisVar(fieldName, sql, javaParamPrefix);
                break;
            case notEqual:
                sql.append(" !=");
                ONGLUtils.buildMybatisVar(fieldName, sql, javaParamPrefix);
                break;
            case equalOrLess:
                sql.append(" &lt;=");
                ONGLUtils.buildMybatisVar(fieldName, sql, javaParamPrefix);
                break;
            case equalOrGreater:
                sql.append(" &gt;=");
                ONGLUtils.buildMybatisVar(fieldName, sql, javaParamPrefix);
                break;
            case less:
                sql.append(" &lt;");
                ONGLUtils.buildMybatisVar(fieldName, sql, javaParamPrefix);
                break;
            case greater:
                sql.append(" &gt;");
                ONGLUtils.buildMybatisVar(fieldName, sql, javaParamPrefix);
                break;
            case isNull:
                sql.append(" is null");
                break;
            case isNotNull:
                sql.append(" is not null");
                break;
        }
    }

    /**
     * 构建前置if test标签
     *
     * @param sql
     * @param fieldName
     * @param fieldClass
     */
    private static void buildIfTestPrefix(SqlBuilder sql, String fieldName, Class fieldClass, String currentJavaParamPrefix) {
        sql.append("\n<if test=\"");
        String param = fieldName;
        Class paramClass = fieldClass;
        sql.append(currentJavaParamPrefix).append(".");
        sql.append(param).append("!=null");
        if (paramClass.isAssignableFrom(CharSequence.class)) {
            sql.append(" and ");
            sql.append(currentJavaParamPrefix).append(".");
            sql.append(param).append(" !=''");
        } else if (paramClass.isAssignableFrom(List.class)) {
            sql.append(" and ");
            sql.append(currentJavaParamPrefix).append(".");
            sql.append(param).append(".").append("size > 0");
        }
        sql.append("\">\n");
    }

}
